package com.tally.user.controller;

import com.alibaba.fastjson.JSON;
import com.tally.server.config.ConstKey;
import com.tally.server.dto.*;
import com.tally.server.enums.EcodeUseEnum;
import com.tally.server.enums.ExpTypeEnum;
import com.tally.server.enums.ResponseCodeEnum;
import com.tally.server.exception.ValidatorException;
import com.tally.server.service.EcodeService;
import com.tally.server.service.UserInfoService;
import com.tally.server.service.UserService;
import com.tally.server.utils.UUIDUtil;
import com.tally.server.utils.ValidatorUtil;
import com.tally.user.mq.MqProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.TimeUnit;

/**
 * @Author: sy
 * @Date: 2020/11/13 20:13
 * @Description:
 */
@RestController
@RequestMapping("/user")
public class UserController {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    public static final String BUSINESS_NAME = "用户";

    @Autowired
    private UserService userService;

    @Autowired
    private EcodeService ecodeService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MqProducer mqProducer;
    
    @Value("${key.expire-time.login}")
    private Long loginExpireTime;

    @Value("${oss.ossDomain}")
    private String ossDomain;

    @PostMapping("/register")
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO register(@RequestBody UserDTO userDTO){
        ValidatorUtil.require(userDTO.getUserName(),"用户名");
        ValidatorUtil.length(userDTO.getUserName(),"用户名",1,50);
        ValidatorUtil.require(userDTO.getPassword(),"密码");
        ValidatorUtil.length(userDTO.getName(),"昵称",1,20);
        ValidatorUtil.require(userDTO.getEmail(),"邮箱");
        ValidatorUtil.length(userDTO.getEmail(),"邮箱",1,50);

        UserDTO userDTODb = userService.findByUserName(userDTO.getUserName());
        if(userDTODb != null){
            return ResponseDTO.fail(ResponseCodeEnum.USER_NAME_EXISTS);
        }

        // 校验邮箱验证码
        EcodeDTO ecodeDTO = new EcodeDTO();
        ecodeDTO.setEmail(userDTO.getEmail());
        ecodeDTO.setCode(userDTO.getEmailCode());
        ecodeDTO.setUse(EcodeUseEnum.REGISTER.getCode());
        ecodeService.validateCode(ecodeDTO);
        logger.info("邮箱验证码校验通过");

        userDTO.setPassword(DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes()));
        userDTO.setPhoto(userDTO.getPhoto());
        userService.save(userDTO);
        return ResponseDTO.success(userDTO);
    }

    @GetMapping("/is-email-exists/{email}")
    public ResponseDTO isEmailExists(@PathVariable String email){
        logger.info("查询邮箱是否存在开始");
        UserDTO userDTO = userService.findByEmail(email);
        if(userDTO == null){
            return ResponseDTO.fail("邮箱号不存在");
        }
        return ResponseDTO.success(null);
    }

    @PostMapping("/reset-password")
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO resetPassword(@RequestBody UserDTO userDTO){
        ValidatorUtil.require(userDTO.getEmail(),"邮箱");
        ValidatorUtil.length(userDTO.getEmail(),"邮箱",1,50);
        ValidatorUtil.require(userDTO.getPassword(),"密码");
        logger.info("用户重置密码开始：{}",userDTO);
        userDTO.setPassword(DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes()));

        // 校验邮箱验证码
        EcodeDTO ecodeDTO = new EcodeDTO();
        ecodeDTO.setEmail(userDTO.getEmail());
        ecodeDTO.setCode(userDTO.getEmailCode());
        ecodeDTO.setUse(EcodeUseEnum.FORGET.getCode());
        ecodeService.validateCode(ecodeDTO);
        logger.info("邮箱验证码校验通过");

        userService.resetPassword(userDTO);
        return ResponseDTO.success(null);
    }

    @PostMapping("/login")
    public ResponseDTO login(@RequestBody UserDTO userDTO){
        ValidatorUtil.require(userDTO.getUserName(),"用户名");
        ValidatorUtil.length(userDTO.getUserName(),"用户名",1,50);
        ValidatorUtil.require(userDTO.getPassword(),"密码");
        userDTO.setPassword(DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes()));

        if(StringUtils.isEmpty(userDTO.getImageCode())){
            logger.info("用户登录失败，验证码为空");
            return ResponseDTO.fail("验证码不能为空");
        }
        String imageCode = (String) redisTemplate.opsForValue().get(userDTO.getImageCodeToken() + ConstKey.IMAGE_CODE_SUFFIX);
        if(StringUtils.isEmpty(imageCode)){
            logger.info("用户{}登录失败，验证码已过期",userDTO);
            return ResponseDTO.fail("验证码已过期");
        }
        if(!imageCode.toLowerCase().equals(userDTO.getImageCode().toLowerCase())){
            logger.info("用户登录失败，验证码不正确");
            return ResponseDTO.fail("验证码不正确");
        }
        redisTemplate.delete(userDTO.getImageCodeToken() + ConstKey.IMAGE_CODE_SUFFIX);

        LoginUserDTO loginUserDTO = userService.login(userDTO);
        String token = UUIDUtil.getShortUUID();
        loginUserDTO.setToken(token);

        mqProducer.addExp(loginUserDTO.getId(), ExpTypeEnum.EXP_LOGIN.getCode());

        redisTemplate.opsForValue().set(token + ConstKey.LOGIN_SUFFIX, JSON.toJSONString(loginUserDTO),loginExpireTime, TimeUnit.SECONDS);

        return ResponseDTO.success(loginUserDTO);
    }

    @GetMapping("/logout/{token}")
    public ResponseDTO logout(@PathVariable String token){
        redisTemplate.delete(token + ConstKey.LOGIN_SUFFIX);
        logger.info("从redis中删除token:{}",token);
        return ResponseDTO.success(null);
    }

    @GetMapping("/get-login-user/{token}")
    public ResponseDTO getLoginUser(@PathVariable String token){
        Object obj = redisTemplate.opsForValue().get(token + ConstKey.LOGIN_SUFFIX);
        if(obj == null){
            logger.info("token无效");
            return ResponseDTO.success(null);
        }
        LoginUserDTO loginUserDTO = JSON.parseObject(String.valueOf(obj), LoginUserDTO.class);
        return ResponseDTO.success(loginUserDTO);
    }

    @GetMapping("/get-user-info/{userId}")
    public ResponseDTO getUserInfo(@PathVariable String userId){
        if(StringUtils.isEmpty(userId)){
            throw new ValidatorException("用户id不能为空");
        }
        Integer uid = parseInt(userId);
        UserInfoDTO userInfoDTO = userInfoService.selectByUserId(uid);
        return ResponseDTO.success(userInfoDTO);
    }

    @PostMapping("/save-user-info")
    @Transactional
    public ResponseDTO saveUserInfo(@RequestBody UserInfoDTO userInfoDTO){
        ValidatorUtil.require(userInfoDTO.getName(),"昵称");
        ValidatorUtil.length(userInfoDTO.getName(),"昵称",1,20);
        ValidatorUtil.require(userInfoDTO.getProvince(),"省");
        ValidatorUtil.require(userInfoDTO.getCity(),"城市");
        ValidatorUtil.require(userInfoDTO.getArea(),"区县");
        ValidatorUtil.length(userInfoDTO.getAboutme(),"个性签名",1,128);

        UserDTO userDTO = new UserDTO();
        userDTO.setId(userInfoDTO.getUserId());
        userDTO.setName(userInfoDTO.getName());
        userService.updateSelective(userDTO);

        userInfoService.save(userInfoDTO);

        mqProducer.addExp(userDTO.getId(),ExpTypeEnum.EXP_SET_USER_INFO.getCode());

        return ResponseDTO.success(null);
    }

    @PostMapping("/set-photo")
    public ResponseDTO setPhoto(@RequestBody LoginUserDTO loginUserDTO){
        if(loginUserDTO==null || StringUtils.isEmpty(loginUserDTO.getPhoto())){
            throw new ValidatorException("请上传图片！");
        }
        userService.setPhoto(loginUserDTO);
        return ResponseDTO.success(null);
    }

    @PostMapping("/modify-password")
    public ResponseDTO modifyPassword(@RequestBody UserModifyDTO userModifyDTO){
        ValidatorUtil.require(userModifyDTO.getOldPassword(),"原始密码");
        ValidatorUtil.require(userModifyDTO.getNewPassword(),"新密码");

        userModifyDTO.setOldPassword(DigestUtils.md5DigestAsHex(userModifyDTO.getOldPassword().getBytes()));
        userModifyDTO.setNewPassword(DigestUtils.md5DigestAsHex(userModifyDTO.getNewPassword().getBytes()));
        userService.modifyPassword(userModifyDTO);
        return ResponseDTO.success(null);
    }

    @GetMapping("/get-name/{id}")
    public ResponseDTO getUserName(@PathVariable String id){
        if(StringUtils.isEmpty(id)){
            throw new ValidatorException("参数出现空值");
        }
        int uid = parseInt(id);
        String userName = userService.getName(uid);
        return ResponseDTO.success(userName);
    }

    @GetMapping("/getUser/{id}")
    public ResponseDTO getUser(@PathVariable String id) {
        if(StringUtils.isEmpty(id)){
            throw new ValidatorException("参数出现空值");
        }
        int uid = parseInt(id);
        UserDTO userDTO = userService.getById(uid);
        return ResponseDTO.success(userDTO);
    }

    private int parseInt(String s){
        int i;
        try{
            i = Integer.parseInt(s);
        }catch (NumberFormatException e){
            throw new ValidatorException(s + "非纯数字！");
        }
        return i;
    }
}
